package com.party.pay;

import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class XunaySignUtil {
    // MD5 加密（大写）
    private static final String MD5_ALGORITHM = "MD5";

    /**
     * 生成签名（MD5）
     * @param paramMap 待签名参数（不含 sign）
     * @param mchKey   商户密钥（从迅支付后台获取）
     * @return 签名值（大写）
     */
    public static String generateSign(Map<String, String> paramMap, String mchKey) {
        try {
            // 1. 按 ASCII 升序排序参数（TreeMap 自动排序）
            Map<String, String> sortedMap = new TreeMap<>(paramMap);

            // 2. 拼接参数：key=value&key=value
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                // 排除空值和 sign 字段
                if (value != null && !value.isEmpty() && !"sign".equals(key)) {
                    sb.append(key).append("=").append(value).append("&");
                }
            }

            // 3. 拼接商户密钥（最后加 &key=密钥）
            sb.append("key=").append(mchKey);

            // 4. MD5 加密并转大写
            MessageDigest md = MessageDigest.getInstance(MD5_ALGORITHM);
            byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
            StringBuilder signSb = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(b & 0xFF);
                if (hex.length() == 1) {
                    signSb.append("0");
                }
                signSb.append(hex);
            }
            return signSb.toString().toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("签名生成失败", e);
        }
    }

    /**
     * 验证响应签名（防止篡改）
     * @param response 退款响应
     * @param mchKey   商户密钥
     * @return true-签名正确，false-签名错误
     */
    public static boolean verifySign(XunayRefundResponse response, String mchKey) {
        if (response.getCode() != 0 || response.getData() == null || response.getSign() == null) {
            return false; // 失败响应无需验签（或按文档要求处理）
        }

        // 1. 将 data 字段转换为 Map
        XunayRefundResponse.RefundData data = response.getData();
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("refundOrderId", data.getRefundOrderId());
        dataMap.put("mchRefundNo", data.getMchRefundNo());
        dataMap.put("mchOrderNo", data.getMchOrderNo());
        dataMap.put("payOrderId", data.getPayOrderId());
        dataMap.put("orderAmount", String.valueOf(data.getOrderAmount()));
        dataMap.put("refundAmount", String.valueOf(data.getRefundAmount()));
        dataMap.put("refundState", String.valueOf(data.getRefundState()));
        dataMap.put("refundReason", data.getRefundReason());
        dataMap.put("refundTime", String.valueOf(data.getRefundTime()));
        if (data.getChannelErrCode() != null) {
            dataMap.put("channelErrCode", data.getChannelErrCode());
        }
        if (data.getChannelErrMsg() != null) {
            dataMap.put("channelErrMsg", data.getChannelErrMsg());
        }

        // 2. 生成待验签字符串并对比
        String expectedSign = generateSign(dataMap, mchKey);
        return expectedSign.equals(response.getSign());
    }
    /**
     * 验证通知签名
     * @param notifyRequest 通知参数对象
     * @param mchKey        商户密钥
     * @return true-签名正确
     */
    public static boolean verifyNotifySign(PayNotifyRequest notifyRequest, String mchKey) {
        String expectedSign = generateSign(notifyRequest.toSignMap(), mchKey);
        return expectedSign.equals(notifyRequest.getSign());
    }
}
